﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;


namespace MSBuildEditor
{
    internal class MSBuildCompletionSource : ICompletionSource
    {
        private MSBuildCompletionSourceProvider m_sourceProvider;
        private ITextBuffer m_textBuffer;

        public MSBuildCompletionSource(MSBuildCompletionSourceProvider sourceProvider, ITextBuffer textBuffer)
        {
            m_sourceProvider = sourceProvider;
            m_textBuffer = textBuffer;
        }



        void ICompletionSource.AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets)
        {
            try
            {
                SnapshotPoint currentPoint = session.TextView.Caret.Position.BufferPosition;
                SnapshotPoint startPoint = new SnapshotPoint(session.TextView.TextSnapshot, 0);
                SnapshotPoint endPoint = new SnapshotPoint(session.TextView.TextSnapshot, session.TextView.VisualSnapshot.Length);
                SnapshotSpan span = new SnapshotSpan(startPoint, endPoint);
                string targetText = span.GetText();
                if (!Intellisense.DisplayManager.IsDisplay(targetText, currentPoint.Position))
                    return;
                Intellisense.SelectedTaskInfo selectedInfo = Intellisense.SelectedDataGetter.GetSelectedTaskInfo(targetText, currentPoint.Position);
                if (selectedInfo == null)
                    return;

                bool isTask = false;
                if (Intellisense.DisplayManager.IsTask(targetText, currentPoint.Position))
                    isTask = true;
                if (isTask)
                {
                    if (!string.IsNullOrWhiteSpace(selectedInfo.ParentXPath))
                    {
                        List<Completion> task_compList = new List<Completion>();
                        List<CompletionData.TaskInfo> taskInfos = CompletionData.DataManager.GetTasks(selectedInfo.ParentXPath);
                        if (taskInfos != null && taskInfos.Count > 0)
                            taskInfos.ForEach(t => task_compList.Add(new Completion(t.Name, t.Name, "", null, null)));
                        
                        completionSets.Add(new CompletionSet(
                            "MSBuild Task",    //the non-localized title of the tab
                            "MSBuild Task",    //the display title of the tab
                            FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                session,
                                selectedInfo,
                                isTask),
                            task_compList,
                            null));

                    }
                }
                else
                {
                    if (Intellisense.DisplayManager.IsProperty(targetText, currentPoint.Position))
                    {
                        List<Completion> taskParams_compList = new List<Completion>();
                        List<CompletionData.PropertyInfo> props = CompletionData.DataManager.GetProperties(selectedInfo.ParentXPath, selectedInfo.TaskName);
                        if (props != null && props.Count > 0)
                            props.ForEach(p =>
                            {
                                if (!selectedInfo.SettingProperties.Contains(p.Name))
                                    taskParams_compList.Add(new Completion(p.Name, p.Name + "=\"\"", "", null, null));
                            });
                        completionSets.Add(new CompletionSet(
                            "MSBuild Task Parameter",    //the non-localized title of the tab
                            "MSBuild Task Parameter",    //the display title of the tab
                            FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                session,
                                selectedInfo,
                                isTask),
                            taskParams_compList,
                            null));

                    }
                    else
                    {
                        if (currentPoint.Position - 2 >= 0)
                        {
                            SnapshotPoint prePoint = new SnapshotPoint(session.TextView.TextSnapshot, currentPoint.Position - 2);
                            SnapshotSpan preSpan = new SnapshotSpan(prePoint, currentPoint);
                            string preText = preSpan.GetText();
                            if (preText == "$(")
                            {
                                List<Completion> reserved_compList = new List<Completion>();
                                List<Completion> envProp_compList = new List<Completion>();
                                CompletionData.ReservedProperties propsInstance = CompletionData.ReservedProperties.GetInstance();
                                IDictionary<string, string> projProps = propsInstance.GetProperties();
                                foreach (string key in projProps.Keys)
                                {
                                    if (key.ToUpper().StartsWith("MSBUILD"))
                                        reserved_compList.Add(new Completion(key, key, projProps[key], null, null));
                                    else
                                        envProp_compList.Add(new Completion(key, key, projProps[key], null, null));
                                }

                                //reserved Property
                                completionSets.Add(new CompletionSet(
                                    "MSBuild Reserved Property",    //the non-localized title of the tab
                                    "MSBuild Reserved Property",    //the display title of the tab
                                    FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                        session,
                                        selectedInfo,
                                        isTask),
                                    reserved_compList,
                                    null));
                                //environment Variable
                                completionSets.Add(new CompletionSet(
                                    "MSBuild Environment Variable",    //the non-localized title of the tab
                                    "MSBuild Environment Variable",    //the display title of the tab
                                    FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                        session,
                                        selectedInfo,
                                        isTask),
                                    envProp_compList,
                                    null));
                            }
                        }
                    }
                }

            }
            catch (Exception)
            {
            }
        }


        private ITrackingSpan FindTokenSpanAtPosition(ITrackingPoint point, ICompletionSession session, Intellisense.SelectedTaskInfo selectedInfo,bool isTask)
        {
            SnapshotSpan taskSpan = new SnapshotSpan(
                new SnapshotPoint(session.TextView.TextSnapshot, selectedInfo.TextSpan.StartPosition),
                new SnapshotPoint(session.TextView.TextSnapshot, selectedInfo.TextSpan.EndPosition));
            string taskText = taskSpan.GetText();

            int backLength = 0;
            if (isTask)
                backLength = selectedInfo.TaskName.Length;
            SnapshotPoint currentPoint = session.TextView.Caret.Position.BufferPosition - backLength;
            SnapshotSpan span = new SnapshotSpan(currentPoint, backLength);

            ITrackingSpan result = currentPoint.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive);
            return result;
        }



        private bool m_isDisposed;
        public void Dispose()
        {
            if (!m_isDisposed)
            {
                GC.SuppressFinalize(this);
                m_isDisposed = true;
            }
        }


    }
}
